package dao.jdbc;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;

import model.Teilnehmer;
import dao.jdbc.JdbcDao.JdbcDAO;

public class TeilnehmerJdbcDao implements JdbcDAO<Teilnehmer> {

  private PreparedStatement updateStatement = null;
  private PreparedStatement insertStatement = null;
  private PreparedStatement deleteStatement = null;
  private PreparedStatement findByIdStatement = null;
  private PreparedStatement findAllStatement = null;
  private PreparedStatement findByTerminIdStatement = null;

  private static final String SQL_INSERT = "INSERT INTO terminplaner.teilnehmer(timestamp,TerminID,vorname,nachname,anrede) "
      + "VALUES(? ,?, ?, ?, ?)";

  private static final String SQL_UPDATE = "UPDATE terminplaner.teilnehmer "
      + "SET timestamp=?, TerminID=?, vorname=?, nachname=?, anrede=? " + "WHERE id=?";

  private static final String SQL_SELECT_BY_ID = "SELECT id, timestamp,TerminID,vorname,nachname,anrede "
      + "FROM terminplaner.teilnehmer " + "WHERE id=?";

  private static final String SQL_SELECT_ALL = "SELECT id, timestamp,TerminID,vorname,nachname,anrede "
      + "FROM terminplaner.teilnehmer";

  private static final String SQL_DELETE_BY_ID = "DELETE FROM terminplaner.teilnehmer " + "WHERE id=?";

  private static final String SQL_SELECT_BY_TERMINID = "SELECT id, timestamp,TerminID,vorname,nachname,anrede "
      + "FROM terminplaner.teilnehmer " + "WHERE TerminID=?";

  @Override
  public int save(Connection con, Teilnehmer data) throws IOException {
    if (con == null)
      throw new IllegalArgumentException("Connection darf nicht null sein!");
    if (data == null)
      throw new IllegalArgumentException("Daten duerfen nicht null sein!");

    int changed = 0;

    if (data.neu())
      changed = insert(con, data, new Date());
    else if (!data.neu())
      changed = update(con, data, new Date());

    return changed;
  }

  private int insert(Connection con, Teilnehmer data, Date timestamp) throws IOException {
    if (timestamp == null)
      throw new IllegalArgumentException("timestamp darf nicht null sein!");

    int recordsAffected = 0;
    try {
      insertStatement = con.prepareStatement(SQL_INSERT, PreparedStatement.RETURN_GENERATED_KEYS);
      
      insertStatement.setTimestamp(1, JdbcDao.toSqlTimestamp(timestamp));

      if (data.getTermin() != null)
        insertStatement.setLong(2, data.getTermin().getId());
      else
        insertStatement.setLong(2, new Long(-999));

      insertStatement.setString(3, data.getVorname());
      insertStatement.setString(4, data.getNachname());
      insertStatement.setString(5, data.getAnrede());

      recordsAffected = insertStatement.executeUpdate();
      ResultSet rs = insertStatement.getGeneratedKeys();

      while (rs.next()) {
        data.setID(rs.getLong(1));
        data.setTimestamp((Date) timestamp.clone());
      }
      
    } catch (SQLException e) {
      throw new IOException("Fehler bei InsertStatement!", e);
    }
    return recordsAffected;
  }

  private int update(Connection con, Teilnehmer data, Date timestamp) throws IOException {
    if (timestamp == null)
      throw new IllegalArgumentException("timestamp darf nicht null sein!");

    int recordsAffected = 0;
    try {
        updateStatement = con.prepareStatement(SQL_UPDATE);

      updateStatement.setTimestamp(1, JdbcDao.toSqlTimestamp(timestamp));

      if (data.getTermin() != null)
        updateStatement.setLong(2, data.getTermin().getId());
      else
        updateStatement.setLong(2, new Long(-999));

      updateStatement.setString(3, data.getVorname());
      updateStatement.setString(4, data.getNachname());
      updateStatement.setString(5, data.getAnrede());

      updateStatement.setLong(6, data.getId());

      
      recordsAffected = updateStatement.executeUpdate();
      data.setTimestamp((Date) timestamp.clone());

    } catch (SQLException e) {
      throw new IOException("Fehler bei UpdateStatement!", e);
    }

    return recordsAffected;
  }

  @Override
  public int delete(Connection con, Teilnehmer data) throws IOException {
    if (con == null)
      throw new IllegalArgumentException("Connection darf nicht null sein!");
    if (data == null)
      throw new IllegalArgumentException("Daten duerfen nicht null sein!");

    int recordsAffected = 0;
    try {
        deleteStatement = con.prepareStatement(SQL_DELETE_BY_ID);

      if (data.getId() == null)
        throw new IllegalArgumentException("Teilnehmer befindet sich nicht in der Datenbank!");

      deleteStatement.setLong(1, data.getId());

      recordsAffected = deleteStatement.executeUpdate();
      data.idLoeschen();

    } catch (SQLException e) {
      throw new IOException("Fehler bei DeleteStatement", e);
    }
    return recordsAffected;

  }

  @Override
  public Teilnehmer findById(Connection con, Long id) throws IOException {
    if (con == null)
      throw new IllegalArgumentException("Connection darf nicht null sein!");
    if (id == null)
      throw new IllegalArgumentException("ID darf nicht null sein");

    Teilnehmer teilnehmer = null;
    try {
        findByIdStatement = con.prepareStatement(SQL_SELECT_BY_ID);
      findByIdStatement.setLong(1, id);

      ResultSet rs = findByIdStatement.executeQuery();
      rs.next();

      teilnehmer = createTeilnehmerFromResultSet(con, rs);

      if (!rs.isLast())
        throw new IOException("Fehler in der Datenstruktur, id darf jeweils nur einmal vorkommen!");

    } catch (SQLException e) {
      throw new IOException("Fehler bei findByID Statement!", e);
    }
    if (teilnehmer == null)
      throw new IOException("Adresse mit dieser ID nicht gefunden!");

    return teilnehmer;
  }

  @Override
  public ArrayList<Teilnehmer> findAll(Connection con) throws IOException {
    if (con == null)
      throw new IllegalArgumentException("Connection darf nicht null sein!");

    ArrayList<Teilnehmer> teilnehmerliste = new ArrayList<Teilnehmer>();
    Teilnehmer teilnehmer = null;

    try {
        findAllStatement = con.prepareStatement(SQL_SELECT_ALL);
      
      ResultSet rs = findAllStatement.executeQuery();
      while (rs.next()) {

        teilnehmer = createTeilnehmerFromResultSet(con, rs);
        teilnehmerliste.add(teilnehmer);

      }

    } catch (SQLException e) {
      throw new IOException("Fehler bei findAll Statement!", e);
    }

    return teilnehmerliste;
  }

  public ArrayList<Teilnehmer> findByTerminId(Connection con, Long terminId) throws IOException {
    if (con == null)
      throw new IllegalArgumentException("Connection darf nicht null sein!");
    if (terminId == null)
      throw new IllegalArgumentException("TerminID darf nicht null sein");

    Teilnehmer teilnehmer = null;
    ArrayList<Teilnehmer> teilnehmerliste = new ArrayList<Teilnehmer>();
    
    try {
        findByTerminIdStatement = con.prepareStatement(SQL_SELECT_BY_TERMINID);

      findByTerminIdStatement.setLong(1, terminId);

      ResultSet rs = findByTerminIdStatement.executeQuery();

      while(rs.next())
      {
       teilnehmer = createTeilnehmerFromResultSet(con, rs);
       teilnehmerliste.add(teilnehmer);
      }
 

    } catch (SQLException e) {
      throw new IOException("Fehler bei findByTerminId Statement!", e);
    }

    return teilnehmerliste;
  }

  private Teilnehmer createTeilnehmerFromResultSet(Connection con, ResultSet rs) throws SQLException, IOException {

    Teilnehmer teilnehmer = null;

    Long id = new Long(rs.getInt("id"));
    String vorname = rs.getString("vorname");
    String nachname = rs.getString("nachname");
    String anrede = rs.getString("anrede");

    teilnehmer = new Teilnehmer(vorname, nachname, anrede);
    teilnehmer.setID(id);
    teilnehmer.setTimestamp(new Date());

    return teilnehmer;

  }
}
